<template>
    <BModal
        dialog-class="tnxbsv-dialog"
        header-class="tnxbsv-dialog-header"
        title-class="tnxbsv-dialog-title"
        body-class="tnxbsv-dialog-body"
        :footer-class="buttons?.length ? 'tnxbsv-dialog-footer' : 'd-none'"
        :data-v-id="id"
        v-model="visible"
        scrollable
        no-close-on-backdrop
        no-close-on-esc
        :teleport-to="container"
        @hidden="onHidden"
    >
        <template #title>
            <div v-html="title" v-if="title"></div>
        </template>
        <div ref="content" v-html="content" v-if="typeof content === 'string'"></div>
        <component ref="content" :is="content" v-bind="contentProps" v-else></component>
        <template #footer>
            <TnxbsvButton v-for="(button, index) in buttons" :key="index"
                :type="button.type || 'light'"
                :loading="buttonLoadings[index]"
                @click="btnClick(index)"
            >
                {{ button.caption || button.text }}
            </TnxbsvButton>
        </template>
    </BModal>
</template>

<script>
import {BModal} from 'bootstrap-vue-next';
import TnxbsvButton from '../button/Button.vue'

export default {
    name: 'TnxbsvDialog',
    components: {BModal, TnxbsvButton,},
    props: {
        id: {
            type: [String, Number],
            default: () => window.tnx.util.string.uuid32(),
        },
        modelValue: {
            type: Boolean,
            default: false,
        },
        container: String,
        title: String,
        content: [String, Object],
        contentProps: {
            type: Object,
            default: () => ({}),
        },
        buttons: Array,
        theme: String,
        width: {
            type: [Number, String],
            default: 512,
        },
    },
    emits: ['update:modelValue', 'close'],
    data() {
        return {
            visible: this.modelValue,
            buttonLoadings: [],
            heightChangeObserver: null,
        };
    },
    watch: {
        modelValue(newValue, oldValue) {
            this.visible = this.modelValue;
            if (newValue && !oldValue) { // 从隐藏到显示
                this.$nextTick(() => {
                    this.locate(true);
                });
            }
        },
        visible() {
            this.$emit('update:modelValue', this.visible);
        },
    },
    mounted() {
        window.tnx.app.eventBus.once('tnx.error', options => {
            this.buttonLoadings = [];
        });
        this.$nextTick(() => {
            if (this.visible) {
                this.locate(true);
            }
        });
    },
    beforeUnmount() {
        window.tnx.app.eventBus.off('tnx.error');
    },
    methods: {
        locate(observe) {
            const $ = window.tnx.libs.$;
            let $dialog = $(`${this.container} .tnxbsv-dialog`);
            if ($dialog.length) {
                let top = window.tnx.util.dom.getTopVerticallyCenteredOnPage($dialog[0]);
                let width = typeof this.width === 'number' ? this.width + 'px' : this.width;
                $dialog.css({
                    'margin-top': top + 'px',
                    'width': width,
                });

                if (observe) {
                    this.heightChangeObserver = window.tnx.util.dom.observeHeightChange($dialog[0], this.locate);
                }
            }
        },
        btnClick(index) {
            const button = this.buttons[index];
            if (button && typeof button.click === 'function') {
                let result = button.click.call(this.$refs.content, this.close);
                if (result === 'loading') {
                    this.buttonLoadings[index] = true;
                    return;
                }
                if (result === false) {
                    return;
                }
            }
            this.close();
        },
        open() {
            this.visible = true;
        },
        close() {
            this.visible = false;
        },
        onHidden() {
            this.$emit('close');
        },
    }
}
</script>

<style>
.tnxbsv-dialog {
    height: fit-content;
    margin-bottom: 0;
    max-width: 100%;
}

.tnxbsv-dialog.modal-dialog-scrollable .modal-content {
    max-height: calc(100vh - 1rem);
}

.tnxbsv-dialog .modal-header {
    padding: 0.75rem 1rem;
}

.tnxbsv-dialog .modal-header .tnxbsv-dialog-title {
    font-size: 1.1rem;
}

.tnxbsv-dialog .modal-header .btn-close {
    --bs-btn-close-opacity: 0.25;
    --bs-btn-close-hover-opacity: 0.5;
}
</style>
